///// Dual Paraboloid Shadow Mapping                 /////
///// Copyright (c) by Christoph P. - gamedevelop.eu /////
///// All rights reserved                            /////
///// allowed for non-commercial use                 /////

#define SHADOW_EPSILON 0.0005f

texture g_DPFrontMap : TEXTURE2DB;
texture g_DPBackMap  : TEXTURE2DC;

texture g_Terrain : TEXTURE2DA;

float4x4 g_mDPView : LITVIEW;  

float4x4 g_mWorldIT : WORLDIT;
float4x4 g_mWorld : WORLD;
float4x4 g_mView  : VIEW;
float4x4 g_mProj  : PROJ;

float g_fFar  = 2048.0f;
float g_fNear = 1.0f;
	
float3 g_vLightPos : LITPOS;

float4 g_Material = float4(1.0f, 1.0f, 1.0f, 1.0f);
float4 g_LightAmbientColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
float4 g_LightDiffuseColor = float4(1.0f, 1.0f, 1.0f, 1.0f);

// DPDepth
sampler2D DPFrontSampler = 
sampler_state
{
	Texture = <g_DPFrontMap>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = Border;
	AddressV = Border;
	BorderColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
};

sampler2D DPBackSampler = 
sampler_state
{
	Texture = <g_DPBackMap>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = Border;
	AddressV = Border;
	BorderColor = float4(0.0f, 0.0f, 0.0f, 1.0f);
};

// DPSM
sampler2D TerrainSampler = 
sampler_state
{
	Texture = <g_Terrain>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
	AddressU = Wrap;
	AddressV = Wrap;
};

// DPSM
struct VSDPSMIn
{
	float3 Pos : POSITION;	
	float2 TexCoord : TEXCOORD0;
	float3 Normal : NORMAL;	
};

struct PSDPSMIn
{
	float4 Pos : POSITION;	
	float3 PosWorld : TEXCOORD0;
	float2 TexCoord : TEXCOORD1;
	float3 Normal : TEXCOORD2;
	float3 Light : TEXCOORD3;
};

// DPSM-vertex-shader
PSDPSMIn DPSMVS(VSDPSMIn In)
{
	PSDPSMIn Out;
	
	// world space
	float3 vPosWorld = mul(float4(In.Pos, 1.0f), g_mWorld);
	
	Out.Normal = normalize(mul(In.Normal, (float3x3)g_mWorldIT));
	Out.Light = normalize(g_vLightPos - vPosWorld);	
	Out.Pos = mul(float4(vPosWorld, 1.0f), mul(g_mView,g_mProj));		
	Out.PosWorld = vPosWorld;
	Out.TexCoord = In.TexCoord;
		
	return Out;
}

// DPSM-pixel-shader
float4 DPSMPS(PSDPSMIn In) : COLOR
{
	float3 Color;
	
	// texcoord-calculation is the same calculation as in the Depth-VS,
	// but texcoords have to be in range [0, 1]
	
	// transform into lightspace
	float3 vPosDP = mul(float4(In.PosWorld, 1.0f), g_mDPView);	
	
	float fLength = length(vPosDP);
	// normalize
	vPosDP /= fLength;
	
	// compute and read according depth
	float fDPDepth;
	float fSceneDepth;
	
	if(vPosDP.z >= 0.0f)
	{		
		float2 vTexFront;
		vTexFront.x =  (vPosDP.x /  (1.0f + vPosDP.z)) * 0.5f + 0.5f; 
		vTexFront.y =  1.0f - ((vPosDP.y /  (1.0f + vPosDP.z)) * 0.5f + 0.5f); 	
		
		fSceneDepth = (fLength - g_fNear) / (g_fFar - g_fNear);
	
		fDPDepth = tex2D(DPFrontSampler, vTexFront).r;			
	}
	else
	{
		// for the back the z has to be inverted		
		float2 vTexBack;
		vTexBack.x =  (vPosDP.x /  (1.0f - vPosDP.z)) * 0.5f + 0.5f; 
		vTexBack.y =  1.0f - ((vPosDP.y /  (1.0f - vPosDP.z)) * 0.5f + 0.5f); 
		
		fSceneDepth = (fLength - g_fNear) / (g_fFar - g_fNear);
		
		fDPDepth = tex2D(DPBackSampler, vTexBack).r;
	}
	
	// lighting and shadowing	
	float3 vNormal = normalize(In.Normal);
	float3 vLight = normalize(In.Light);
	float  intensity = saturate(dot(vLight, vNormal));
		
	if((fDPDepth + SHADOW_EPSILON) < fSceneDepth)
	{
		Color = tex2D(TerrainSampler, In.TexCoord) * float4(0.6f,0.6f,0.8f,1.0f);
	}
	else
	{
		Color = tex2D(TerrainSampler, In.TexCoord)
				/* intensity*/ * g_LightDiffuseColor
				* g_Material + g_LightAmbientColor;
	}
	
	return float4(Color, 1.0f);
}

float4 Wireframe(PSDPSMIn In) : COLOR0
{
	return float4(0,1,0,0.1f);
}

technique DPSM
{
	pass p0
	{
		VertexShader = compile vs_3_0 DPSMVS();
		PixelShader  = compile ps_3_0 DPSMPS();
	}
	//pass p1
	//{
		//FillMode = WireFrame;
		//VertexShader = compile vs_3_0 DPSMVS();
		//PixelShader  = compile ps_3_0 Wireframe();
	//}
}